﻿using AutoMapper;
using System.Text.Json;
using System.Web;
using TrackSystem.Contracts;
using TrackSystem.IO.Utils;

namespace TrackSystem.UI.Server.HttpRepository
{
    public class HttpRepository<TViewDto, TUpdateDto> : IHttpRepository<TViewDto, TUpdateDto>
    {
        private readonly HttpClient _client;
        private readonly IMapper _mapper;
        protected string Name { get; init; } = "";

        protected HttpRepository(HttpClient client, IMapper mapper)
        {
            this._client = client;
            this._mapper = mapper;
        }

        public static HttpRepository<TViewDto, TUpdateDto> CreateInstance(HttpClient client, IMapper mapper)
        {
            return new HttpRepository<TViewDto, TUpdateDto>(client, mapper);
        }

        public async Task<IEnumerable<TViewDto>> GetAll()
        {
            var response = await _client.GetAsync($"api/{Name}/all");
            var content = await response.Content.ReadAsStringAsync();
            var items = JsonSerializer.Deserialize<IEnumerable<TViewDto>>(
                content,
                new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
            return items ??= [];
        }

        public async Task<TViewDto?> GetById(int id)
        {
            var response = await _client.GetAsync($"api/{Name}/{id}");
            var content = await response.Content.ReadAsStringAsync();
            var item = JsonSerializer.Deserialize<TViewDto>(
                content,
                new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
            return item;
        }

        public async Task<ApiResult<TViewDto>> InsertAsync(TUpdateDto equip)
        {
            var eqp = _mapper.Map<TViewDto>(equip);
            var response = await _client.PutAsJsonAsync($"api/{Name}", eqp);
            var content = await response.Content.ReadAsStringAsync();
            var result = JsonSerializer.Deserialize<ApiResult<TViewDto>>(
                content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
            return result ??= ApiResult<TViewDto>.Fail($"{Name} Insert Error", 500);
        }

        public async Task<ApiResult<TViewDto>> UpdateAsync(TUpdateDto equip)
        {
            var eqp = _mapper.Map<TViewDto>(equip);
            var response = await _client.PostAsJsonAsync($"api/{Name}", eqp);
            var content = await response.Content.ReadAsStringAsync();
            var result = JsonSerializer.Deserialize<ApiResult<TViewDto>>(
                content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
            return result ??= ApiResult<TViewDto>.Fail($"{Name} Update Error", 500);
        }

        public async Task<ApiResult<TViewDto>> DeleteAsync(int id)
        {
            var response = await _client.DeleteAsync($"api/{Name}/{id}");
            var content = await response.Content.ReadAsStringAsync();
            var result = JsonSerializer.Deserialize<ApiResult<TViewDto>>(
                content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
            return result ??= ApiResult<TViewDto>.Fail($"{Name} Delete Error", 500);
        }

        public async Task<FormulaResult> TestForula(string expression)
        {
            string encodeUrl = HttpUtility.UrlEncode(expression);
            var response = await _client.GetAsync($"api/vardef/test?formula={encodeUrl}");
            var content = await response.Content.ReadAsStringAsync();
            var result = JsonSerializer.Deserialize<FormulaResult>(
                content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

            return result ??= new FormulaResult();
        }
    }
}
